<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Text and Fonts</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Java 2D, Java, tutorial, text, fonts, programming, Graphics, multiplatform">
<meta name="description" content="In this part of the Java 2D tutorial, we work with text and fonts.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>


<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Text and Fonts</h1>

<p>
In this part of the Java 2D tutorial, we will work with texts and fonts. 
</p>


<h2>Text and fonts</h2>

<p>
Rendering text is another pretty complicated topic. It would easily fill 
a specialized book. Here we only provide some basic examples. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* top_horizontal */
google_ad_slot = "3327173442";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>
A <b>character</b> is a symbol that represents an item such as a letter, 
a digit, or punctuation. A <b>glyph</b> is a shape used to render a character 
or a sequence of characters. In Latin alphabet a glyph typically represents 
one character. In other writing systems, a character may be composed of several 
glyphs. Like ť, ž, ú, ô. These are latin characters with accents. 
</p>

<p>
There are basically two types of fonts. Physical and logical. <b>Physical</b> 
fonts are the actual font libraries. <b>Logical</b> fonts are the five font 
families defined by the Java platform. Serif, SansSerif, Monospaced, Dialog, 
and DialogInput. Logical fonts are not actual font libraries. Logical font 
names are mapped to physical fonts by the Java runtime environment. 
</p>

<p>
Text can be drawn on the window using various fonts. A <b>font</b> is a set of 
type characters of a particular typeface design and size. Various typefaces include 
Helvetica, Georgia, Times or Verdana. A collection of glyphs with a particular 
style form a <b>font face</b>. A collection of font faces forms a <b>font family</b>. 
(java.sun.com, answers.com)
</p>


<h2>System fonts</h2>

<p>
This console example will print all available fonts on your platform. 
</p>

<div class="codehead">AllFonts.java</div>
<pre class="code">
package com.zetcode;

import java.awt.Font;
import java.awt.GraphicsEnvironment;

public class AllFonts {

  public static void main(String[] args) throws Exception {

    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    Font[] fonts = ge.getAllFonts();

    for (int i = 0; i &lt; fonts.length; i++) {
      System.out.print(fonts[i].getFontName() + " : ");
      System.out.print(fonts[i].getFamily() + " : ");
      System.out.print(fonts[i].getName());
      System.out.println();
    }
  }
}
</pre>

<p>
Get all fonts. 
</p>

<pre class="explanation">
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
</pre>

<p>

There are objects that are typical for a particular platform. Fonts are 
among these objects. The collection of fonts on a Unix, OS X and Windows 
platform differ. The <code>GraphicsEnvironment</code> class describes 
the collection <code>GraphicsDevice</code> objects and <code>Font</code> 
objects available on a particular platform.
</p>

<pre class="explanation">
Font[] fonts = ge.getAllFonts();
</pre>

<p>
The <code>getAllFonts()</code> returns all fonts available in the 
<code>GraphicsEnvironment</code>.
</p>

<pre>
 ...
 Purisa : Purisa : Purisa
 Rasheeq-Bold : Rasheeq-Bold : Rasheeq-Bold
 Rehan : Rehan : Rehan
 Rekha-normal : Rekha : Rekha-normal
 Saab : Saab : Saab
 Salem : Salem : Salem
 Samanata : Samanata : Samanata
 SansSerif.bold : SansSerif : SansSerif.bold
 SansSerif.bolditalic : SansSerif : SansSerif.bolditalic
 SansSerif.italic : SansSerif : SansSerif.italic
 SansSerif.plain : SansSerif : SansSerif.plain
 Serif.bold : Serif : Serif.bold
 Serif.bolditalic : Serif : Serif.bolditalic
 Serif.italic : Serif : Serif.italic
 Serif.plain : Serif : Serif.plain
 ...
</pre>

<p>
This is an excerpt of all fonts on Ubuntu Linux. 
</p>


<h2>Soulmate</h2>

<p>
We will display some lyrics on the panel. 
</p>

<div class="codehead">Soulmate.java</div>
<pre class="code">
package com.zetcode;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Soulmate extends JPanel {


    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        RenderingHints rh =
            new RenderingHints(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
               RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHints(rh);

        g2d.setFont(new Font("Purisa", Font.PLAIN, 13));

        g2d.drawString("Most relationships seem so transitory", 20, 30);
        g2d.drawString("They're all good but not the permanent one", 20, 60);
        g2d.drawString("Who doesn't long for someone to hold", 20, 90);
        g2d.drawString("Who knows how to love you without being told", 20, 120);
        g2d.drawString("Somebody tell me why I'm on my own", 20, 150);
        g2d.drawString("If there's a soulmate for everyone", 20, 180);

    }
 
    public static void main(String[] args) {

        JFrame frame = new JFrame("Soulmate");
        frame.add(new Soulmate());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(420, 250);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
</pre>

<p>
Soulmate. 
</p>

<pre class="explanation">
g2d.setFont(new Font("Purisa", Font.PLAIN, 13));
</pre>

<p>
We specify font type.
</p>

<pre class="explanation">
g2d.drawString("Most relationships seem so transitory", 20, 30);
</pre>

<p>
The <code>drawString()</code> method renders the text  using the current 
text attribute state in the <code>Graphics2D</code> context. 
</p>

<img src="/img/gfx/java2d/soulmate.png" alt="Soulmate">
<div class="figure">Figure: Soulmate</div>


<h2>Unicode</h2>

<p>
The next example demonstrates, how to display unicode text. 
</p>

<pre>
$ cat fyodor
Фёдор Михайлович Достоевский родился 30 октября (11 ноября) 1821 года в Москве. 
Был вторым из 7 детей. Отец, Михаил Андреевич, работал в госпитале для бедных. 
...
</pre>

<p>
We have a file called fyodor where we have the text in azbuka.
</p>

<pre>
$ native2ascii fyodor unicode
</pre>

<p>
We use the tool called <code>native2ascii</code>, which can be 
found in the bin directory of the jdk. It converts a file with native-encoded 
characters to one with Unicode-encoded characters. The first parameter is the 
input file. The second parameter is the output file. 
</p>

<pre>
$ cat unicode
\u0424\u0451\u0434\u043e\u0440 \u041c\u0438\u0445\u0430\u0439\u043b\u043e\u0432\u0438\u0447 
...
</pre>

<p>
The same text in unicode encoding. 
</p>

<div class="codehead">Unicode.java</div>
<pre class="code">
package com.zetcode;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Unicode extends JPanel {

    String sent1 = "\u0424\u0451\u0434\u043e\u0440 \u041c\u0438\u0445" +
"\u0430\u0439\u043b\u043e\u0432\u0438\u0447 \u0414\u043e\u0441\u0442" +
"\u043e\u0435\u0432\u0441\u043a\u0438\u0439 \u0440\u043e\u0434\u0438" +
"\u043b\u0441\u044f 30 \u043e\u043a\u0442\u044f\u0431\u0440\u044f " +
"(11 \u043d\u043e\u044f\u0431\u0440\u044f) 1821 \u0433\u043e\u0434" +
"\u0430 \u0432 \u041c\u043e\u0441\u043a\u0432\u0435. ";

    String sent2 = "\u0411\u044b\u043b \u0432\u0442\u043e\u0440\u044b\u043c " +
"\u0438\u0437 7 \u0434\u0435\u0442\u0435\u0439. \u041e\u0442\u0435\u0446, " +
"\u041c\u0438\u0445\u0430\u0438\u043b \u0410\u043d\u0434\u0440\u0435\u0435" +
"\u0432\u0438\u0447, \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0432 " +
"\u0433\u043e\u0441\u043f\u0438\u0442\u0430\u043b\u0435 \u0434\u043b\u044f " +
"\u0431\u0435\u0434\u043d\u044b\u0445."; 

    String sent3 = "\u041c\u0430\u0442\u044c, \u041c\u0430\u0440\u0438\u044f " +
"\u0424\u0451\u0434\u043e\u0440\u043e\u0432\u043d\u0430 " +
"(\u0432 \u0434\u0435\u0432\u0438\u0447\u0435\u0441\u0442\u0432\u0435 " +
"\u041d\u0435\u0447\u0430\u0435\u0432\u0430), \u043f\u0440\u043e\u0438\u0441" +
"\u0445\u043e\u0434\u0438\u043b\u0430 \u0438\u0437 \u043a\u0443\u043f\u0435" +
"\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430.";

    String sent4 = "\u041a\u043e\u0433\u0434\u0430 \u0414\u043e\u0441\u0442" +
"\u043e\u0435\u0432\u0441\u043a\u043e\u043c\u0443 \u0431\u044b\u043b\u043e 15 " +
"\u043b\u0435\u0442, \u0435\u0433\u043e \u043c\u0430\u0442\u044c " +
"\u0443\u043c\u0435\u0440\u043b\u0430 \u043e\u0442 \u0447\u0430\u0445\u043e" +
"\u0442\u043a\u0438, \u0438 \u043e\u0442\u0435\u0446 \u043e\u0442\u043f\u0440" +
"\u0430\u0432\u0438\u043b";

    String sent5 = "\u0441\u0442\u0430\u0440\u0448\u0438\u0445 \u0441\u044b" +
"\u043d\u043e\u0432\u0435\u0439, \u0424\u0451\u0434\u043e\u0440\u0430 \u0438 " +
"\u041c\u0438\u0445\u0430\u0438\u043b\u0430 (\u0432\u043f\u043e\u0441\u043b" +
"\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u0442\u0430\u043a\u0436\u0435 " +
"\u0441\u0442\u0430\u0432\u0448\u0435\u0433\u043e \u043f\u0438\u0441\u0430" +
"\u0442\u0435\u043b\u0435\u043c),"; 

    String sent6 = "\u0432 \u043f\u0430\u043d\u0441\u0438\u043e\u043d \u041a. " +
"\u0424. \u041a\u043e\u0441\u0442\u043e\u043c\u0430\u0440\u043e\u0432\u0430 " +
"\u0432 \u041f\u0435\u0442\u0435\u0440\u0431\u0443\u0440\u0433\u0435.";

    public void paint(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        RenderingHints rh =
            new RenderingHints(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
               RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHints(rh);

        g2d.setFont(new Font("Franklin Gothic Medium", Font.PLAIN, 11));

        g2d.drawString(sent1, 20, 30);
        g2d.drawString(sent2, 20, 55);
        g2d.drawString(sent3, 20, 80);
        g2d.drawString(sent4, 20, 120);
        g2d.drawString(sent5, 20, 145);
        g2d.drawString(sent6, 20, 170);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Unicode");
        frame.add(new Unicode());
        frame.setSize(520, 220);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
</pre>

<p>
Note, that the text would go outside source code in real world programs. Here the text is 
kept inside the source for simplicity reasons. 
</p>


<pre class="explanation">
String sent1 = "\u0424\u0451\u0434\u043e\u0440 \u041c\u0438\u0445" +
...
</pre>

<p>
This is the first unicode line. 
</p>


<pre class="explanation">
g2d.drawString(sent1, 20, 30);
</pre>

<p>
And the sentence is drawn. 
</p>


<img src="/img/gfx/java2d/unicode.png" alt="Unicode">
<div class="figure">Figure: Unicode</div>


<h2>Shadow text</h2>

<p>
In the next example, we will create a shadowed text. The effect is created by drawing 
the same text two times. One text serves as the main text, the other one
as a shadow. The shadowed text is moved a bit, coloured in light gray and blurred. 
</p>

<div class="codehead">ShadowText.java</div>
<pre class="code">
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;


public class ShadowText extends JFrame {

    private int width = 490;
    private int height = 150;

    private String text = "Disciplin ist macht";
    private TextLayout textLayout;


    public ShadowText() throws IOException {

        BufferedImage image = createImage();
        add(new JLabel(new ImageIcon(image)));

        setTitle("Shadowed Text");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }


    static void setRenderingHints(Graphics2D g) {
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                           RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                           RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    }


    public BufferedImage createImage() throws IOException {

        int x = 10;
        int y = 100;

        Font font = new Font("Georgia", Font.ITALIC, 50);
        BufferedImage image =
            new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g1 = image.createGraphics();
        setRenderingHints(g1);
        textLayout = new TextLayout(text, font, g1.getFontRenderContext());
        g1.setPaint(Color.WHITE);
        g1.fillRect(0, 0, width, height);

        g1.setPaint(new Color(150, 150, 150));
        textLayout.draw(g1, x+3, y+3);
        g1.dispose();

        float[] kernel = {
          1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 
          1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f 
        };

        ConvolveOp op =
            new ConvolveOp(new Kernel(3, 3, kernel), ConvolveOp.EDGE_NO_OP,
                           null);
        BufferedImage image2 = op.filter(image, null);

        Graphics2D g2 = image2.createGraphics();
        setRenderingHints(g2);
        g2.setPaint(Color.BLACK);
        textLayout.draw(g2, x, y);

        return image2;
    }

    public static void main(String[] args) throws IOException {
        new ShadowText();
    }
}
</pre>

<p>
This time, we don't draw in the <code>paint()</code> method. 
We create a image, that we put inside a <code>JLabel</code>. 
</p>

<pre class="explanation">
Font font = new Font("Georgia", Font.ITALIC, 50);
</pre>

<p>
Our font is Georgia, italic, of 50 points size. 
</p>

<pre class="explanation">
BufferedImage image =
    new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
</pre>

<p>
We create the first buffered image. 
</p>


<pre class="explanation">
Graphics2D g1 = image.createGraphics();
</pre>

<p>
<code>Graphics2D</code> object is created, which is used to draw into the buffered image. 
</p>

<pre class="explanation">
textLayout = new TextLayout(text, font, g1.getFontRenderContext());
</pre>

<p>
We create a <code>TextLayout</code> class. TextLayout is an immutable 
graphical representation of styled character data. It is used for advanced 
manipulation with the text and font. 
</p>

<pre class="explanation">
textLayout.draw(g1, x+3, y+3);
</pre>

<p>
The code renders this <code>TextLayout</code> at the specified 
location in the specified <code>Graphics2D</code> context. 
The origin of the layout is placed at x, y.
</p>

<pre class="explanation">
float[] kernel = {
  1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 
  1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f, 1f / 9f 
};
 
ConvolveOp op =
    new ConvolveOp(new Kernel(3, 3, kernel), ConvolveOp.EDGE_NO_OP,
                   null);
</pre>

<p>
This creates the blur effect. 
</p>

<pre class="explanation">
BufferedImage image2 = op.filter(image, null);
</pre>

<p>
We apply the blur effect on the first image and copy the outcome to the second buffered image. 
</p>

<pre class="explanation">
textLayout.draw(g2, x, y);
</pre>

<p>
At this point, we have both the original text and the blurred text in 
the <code>TaxLayout</code> object. 
</p>

<pre class="explanation">
add(new JLabel(new ImageIcon(image)));
</pre>

<p>
We put the image inside a <code>JLabel</code>. And the label 
inside the <code>JFrame</code>. 
</p>


<img src="/img/gfx/java2d/shadowtext.png" alt="Shadow Text">
<div class="figure">Figure: Shadow text</div>



<h2>Text attributes</h2>

<p>
When we draw text, we can control various its attributes. We can modify 
text rendering with <code>Font</code> class, <code>TextAttributes</code>, 
<code>AttributeString</code> classes. The Font class represents fonts, 
which are used to render text. The TextAttribute class defines attribute keys and attribute 
values used for text rendering. Finally, the AttributedString class holds 
text and related attribute information. 
</p>

<div class="codehead">TextAttributes.java</div>
<pre class="code">
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;

import java.text.AttributedString;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class TextAttributes extends JPanel {

  String words = "Valour fate kinship darkness";
  String java = "Java TM";

  public void paint(Graphics g) {

    Graphics2D g2d = (Graphics2D) g;

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

    Font font = new Font("Serif", Font.PLAIN, 40);

    AttributedString as1 = new AttributedString(words);
    as1.addAttribute(TextAttribute.FONT, font);

    as1.addAttribute(TextAttribute.FOREGROUND, Color.red, 0, 6);
    as1.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 7, 11);
    as1.addAttribute(TextAttribute.BACKGROUND, Color.LIGHT_GRAY, 12, 19);
    as1.addAttribute(TextAttribute.STRIKETHROUGH,
        TextAttribute.STRIKETHROUGH_ON, 20, 28);

    g2d.drawString(as1.getIterator(), 15, 60);

    AttributedString as2 = new AttributedString(java);

    as2.addAttribute(TextAttribute.SIZE, 40);
    as2.addAttribute(TextAttribute.SUPERSCRIPT, 
        TextAttribute.SUPERSCRIPT_SUPER, 5, 7);

    g2d.drawString(as2.getIterator(), 130, 125);
  }

  public static void main(String[] args) {
    JFrame frame = new JFrame("Text attributes");
        frame.add(new TextAttributes());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setSize(620, 190);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
  }
}
</pre>

<p>
In our example, we demonstrate various text rendering possibilities. 
</p>

<pre class="explanation">
AttributedString as1 = new AttributedString(words);
</pre>

<p>
We create an <code>AttributeString</code> out of the <code>words</code> string. 
</p>

<pre class="explanation">
as1.addAttribute(TextAttribute.FOREGROUND, Color.red, 0, 6);
</pre>

<p>
Here we add a new attribute to the <code>AttributeString</code> class. T
his attribute says, that the first seven characters will be rendered in red color. 
</p>

<pre class="explanation">
g2d.drawString(as1.getIterator(), 15, 60);
</pre>

<p>
The first text is drawn on the panel. Because at the moment we work with a 
<code>AttributeString</code> class and not directly with the string, 
we use an overloaded <code>drawString()</code> method, which takes a 
<code>AttributedCharacterIterator</code> instance as its first parameter. 
</p>


<img src="/img/gfx/java2d/textattributes.png" alt="Text Attributes">
<div class="figure">Figure: Text Attributes</div>


<h2>Rotated Text</h2>

<p>
In the last example, we will show a rotated text on the panel. 
To rotate a text, we will do rotation and translation operations. 
As we already stated, a <code>glyph</code> is a shape used to 
render a character. So in our code example, we need to get all glyphs 
of our text, get their measurements and manipulate them one by one.
</p>

<p>
We will work with several important classes. The <code>FontRenderContext</code> 
class is a container for the information needed to correctly measure text. 
The <code>GlyphVector</code> object is a collection of glyphs containing 
geometric information for the placement of each glyph in a transformed coordinate space.
</p>

<div class="codehead">RotatedText.java</div>
<pre class="code">
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class RotatedText extends JPanel {

  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

    String s = "ZetCode, tutorials for programmers";

    Font font = new Font("Courier", Font.PLAIN, 12);

    g2d.translate(20, 20);

    FontRenderContext frc = g2d.getFontRenderContext();

    GlyphVector gv = font.createGlyphVector(frc, s);
    int length = gv.getNumGlyphs();

    for (int i = 0; i &lt; length; i++) {
      Point2D p = gv.getGlyphPosition(i);
      double theta = (double) i / (double) (length - 1) * Math.PI / 3;
      AffineTransform at = AffineTransform.getTranslateInstance(p.getX(),
          p.getY());
      at.rotate(theta);

      Shape glyph = gv.getGlyphOutline(i);
      Shape transformedGlyph = at.createTransformedShape(glyph);
      g2d.fill(transformedGlyph);
    }
  }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Rotated text");
        frame.add(new RotatedText());
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
  }
}
</pre>

<p>
Rotated text example. 
</p>

<pre class="explanation">
String s = "ZetCode, tutorials for programmers";
</pre>

<p>
This is our text. Because the text is in Latin1 encoding, glyphs 
correspond to characters in a one-to-one manner.
</p>

<pre class="explanation">
GlyphVector gv = font.createGlyphVector(frc, s);
</pre>

<p>
Here we create a <code>GlyphVector</code> object. A GlyphVector 
is a collection of glyphs and their positions.
</p>

<pre class="explanation">
int length = gv.getNumGlyphs();
</pre>

<p>
Here we get the number of glyphs of our text. If we print the number to 
the console, we get 34. So each character is a glyph, for our text. 
</p>

<pre class="explanation">
Point2D p = gv.getGlyphPosition(i);
</pre>

<p>
We iterate through the vector of glyphs. For each glyph we calculate its position. 
</p>

<pre class="explanation">
double theta = (double) i / (double) (length - 1) * Math.PI / 3;
</pre>

<p>
We calculate the degree, by which the glyph is going to be rotated. 
</p>

<pre class="explanation">
AffineTransform at = AffineTransform.getTranslateInstance(p.getX(),
    p.getY());
at.rotate(theta);
</pre>

<p>
We do an affine rotate transformation. Or better said, we create an affine transformation object. 
</p>

<pre class="explanation">
Shape glyph = gv.getGlyphOutline(i);
Shape transformedGlyph = at.createTransformedShape(glyph);
</pre>

<p>
The <code>getGlyphOutline()</code> method returns a <code>Shape</code> 
of the specified glyph. The <code>createTransformedShape()</code> method returns 
a new Shape object modified by our affine transform operation.
</p>

<pre class="explanation">
g2d.fill(transformedGlyph);
</pre>

<p>
Finally, we paint the glyph. 
</p>

<img src="/img/gfx/java2d/rotatedtext.png" alt="Rotated text">
<div class="figure">Figure: Rotated text</div>


<p>
In this part of the Java 2D tutorial, we covered Text and Fonts.
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>

<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified November 25, 2008  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

